#![windows_subsystem = "windows"]
extern crate native_windows_derive as nwd;
extern crate native_windows_gui as nwg;

use std::{
    cell::RefCell,
    fs,
    time::{SystemTime, UNIX_EPOCH},
};

use ini::Ini;
use nwd::NwgUi;

use nwg::NativeUi;

use serde_json::Value;

const OPEN_URL: &str = "https://www.91demo.top/api/open";

static EMBEDDED_IMAGE2: &[u8] = include_bytes!(".\\..\\images\\visit.jpg");

#[derive(Default)]
struct MyData {
    icode: String,
    isecret: String,
    token: String,
    expire_at: u64,
    md_file: String,
}

fn get_ts() -> u64 {
    let time = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_secs();
    return time;
}

fn get_token(icode: &str, isecret: &str) -> Result<String, anyhow::Error> {
    let token_url = format!("{}/vtoken?icode={}&isecret={}", OPEN_URL, icode, isecret);
    let resp: Value = ureq::get(token_url.as_str()).call()?.into_json()?;
    println!("the resp is {}", resp);
    let jcode = &resp["code"];
    let jmsg = &resp["msg"];
    let code = jcode.as_i64().unwrap();
    if code != 1 {
        let msg = jmsg.as_str().unwrap();
        let err_msg = format!("error info is {{ msg:{}}}", msg);
        anyhow::bail!(err_msg)
    }
    let jdata = &resp["data"];
    let data = jdata.as_str().unwrap();
    Ok(data.to_owned())
}

fn upload_art(
    token: &str,
    md_file: &str,
    title: &str,
    kw: &str,
    pub_state: u8,
    lock_state: u8,
) -> Result<(), anyhow::Error> {
    let content = fs::read_to_string(md_file)?;
    let upart_url = format!("{}/upVArt?token={}", OPEN_URL, token);
    let resp: Value = ureq::post(upart_url.as_str())
        .send_json(ureq::json!({
            "title": title,
            "keyword": kw,
            "content":content,
            "islock":lock_state,
            "ispub":pub_state,
        }))?
        .into_json()?;

    println!("the resp is {}", resp);

    let jcode = &resp["code"];
    let jmsg = &resp["msg"];
    let code = jcode.as_i64().unwrap();
    if code != 1 {
        let msg = jmsg.as_str().unwrap();
        let err_msg = format!("error info is {{ msg:{}}}", msg);
        anyhow::bail!(err_msg)
    }
    Ok(())
}

#[derive(Default, NwgUi)]
pub struct MainApp {
    #[nwg_control(size: (480, 490), position: (300, 300), title: "【豆子碎片】文章上传小工具", accept_files: true,flags: "WINDOW|VISIBLE")]
    #[nwg_events( OnWindowClose: [MainApp::exit],OnFileDrop:[MainApp::load_file(SELF,EVT_DATA)],OnInit: [MainApp::load_data] )]
    window: nwg::Window,

    #[nwg_resource(family: "Arial", size: 16)]
    arial16: nwg::Font,

    #[nwg_resource(family: "Arial", size: 14)]
    arial14: nwg::Font,

    #[nwg_resource]
    decoder: nwg::ImageDecoder,

    #[nwg_layout(parent: window ,spacing:1)]
    layout: nwg::GridLayout,

    #[nwg_control(text: "请把Markdown文件拖拽到这里", font: Some(&data.arial16))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:4, row: 0,row_span:2)]
    lbl_apk: nwg::Label,

    #[nwg_control()]
    #[nwg_layout_item(layout: layout, col: 4, row: 0, col_span: 2, row_span: 2)]
    img_mp: nwg::ImageFrame,

    #[nwg_control(text: "请输入标题：", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:2, row: 2)]
    lbl_title: nwg::Label,

    #[nwg_control(text: "", size: (280, 35), position: (10, 10), focus: true)]
    #[nwg_layout_item(layout: layout, col: 2,col_span:4, row: 2)]
    edt_title: nwg::TextInput,

    #[nwg_control(text: "请输入关键字：", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:2, row: 3)]
    lbl_kw: nwg::Label,

    #[nwg_control(text: "")]
    #[nwg_layout_item(layout: layout, col: 2,col_span:4, row: 3)]
    edt_kw: nwg::TextInput,

    #[nwg_control(text: "是否公开：", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:2, row: 4)]
    lbl_pub: nwg::Label,

    #[nwg_control(text: "", check_state: CheckBoxState::Unchecked)]
    #[nwg_layout_item(layout: layout, col: 2,col_span:1, row: 4)]
    chx_pub: nwg::CheckBox,

    #[nwg_control(text: "是否加锁：", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:2, row: 5)]
    lbl_lock: nwg::Label,

    #[nwg_control(text: "", check_state: CheckBoxState::Unchecked)]
    #[nwg_layout_item(layout: layout, col: 2,col_span:1, row: 5)]
    chx_lock: nwg::CheckBox,

    #[nwg_control(text: "在豆子笔记（https://www.91demo.top）查看API接口文档。", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:6, row: 6,row_span:1)]
    lbl_help1: nwg::Label,

    #[nwg_control(text: "扫码小程序码查看文章上传效果。", font: Some(&data.arial14))]
    #[nwg_layout_item(layout: layout, col: 0,col_span:4, row: 7,row_span:1)]
    lbl_help2: nwg::Label,

    #[nwg_control(text: "提交", size: (280, 70), position: (10, 50))]
    #[nwg_layout_item(layout: layout, col: 4,col_span:2, row: 7)]
    #[nwg_events( OnButtonClick: [MainApp::upload_art] )]
    btn_upgrade: nwg::Button,

    my_data: RefCell<MyData>,
}

impl MainApp {
    fn load_data(&self) {
        let wimg = &self.img_mp;
        println!("1-{:?}", wimg.size());
        let wdata = self.decoder.from_stream(EMBEDDED_IMAGE2).unwrap();
        let wframedata = wdata.frame(0).unwrap();
        let wndata = self.decoder.resize_image(&wframedata, [116, 116]).unwrap();
        let wnbm = wndata.as_bitmap().unwrap();
        wimg.set_bitmap(Some(&wnbm));
        let conf = Ini::load_from_file("conf.ini").expect("please config conf.ini file");
        let section = conf.section(Some("User")).unwrap();
        let icode = section.get("icode").unwrap();
        let isecret = section.get("isecret").unwrap();
        let token = section.get("token").unwrap();
        let expire_at: u64 = section.get("expire_at").unwrap().trim().parse().unwrap();
        let my_data = MyData {
            icode: String::from(icode),
            isecret: String::from(isecret),
            token: token.to_string(),
            md_file: "".to_string(),
            expire_at,
        };
        *self.my_data.borrow_mut() = my_data;
    }
    pub fn load_file(&self, data: &nwg::EventData) {
        let drop = data.on_file_drop();
        let files = drop.files();
        if files.len() != 1 {
            nwg::modal_error_message(&self.window, "提示", "仅支持单个文件");
            return;
        }

        let new_file = files[0].clone();

        if !new_file.contains(".md") {
            nwg::modal_error_message(&self.window, "提示", "请上传Markdown文件");
            return;
        }
        let mut my_data = self.my_data.borrow_mut();
        my_data.md_file = new_file;

        self.lbl_apk.set_text(&files[0]);
    }

    fn upload_art(&self) {
        let mut my_data = self.my_data.borrow_mut();
        let token = &my_data.token;
        let expire_at = my_data.expire_at;
        let now = get_ts();

        if token.is_empty() || now > expire_at {
            // 获取token
            if my_data.icode.is_empty() || my_data.isecret.is_empty() {
                nwg::modal_error_message(&self.window, "提示", "配置文件内容为空");
                return;
            }

            let result = get_token(&my_data.icode, &my_data.isecret);
            match result {
                Ok(token) => {
                    my_data.token = token.clone();
                    let expire_at = now + 7000;
                    my_data.expire_at = expire_at;
                    let mut conf = Ini::new();
                    conf.with_section(Some("User"))
                        .set("icode", my_data.icode.clone())
                        .set("isecret", my_data.isecret.clone())
                        .set("token", token)
                        .set("expire_at", expire_at.to_string());
                    conf.write_to_file("conf.ini").unwrap();

                    if my_data.md_file.is_empty() {
                        nwg::modal_error_message(&self.window, "提示", "Markdown文件为空");
                        return;
                    }
            
                    let title = self.edt_title.text();
                    if title == "" {
                        nwg::modal_error_message(&self.window, "提示", "标题为空");
                        return;
                    }
            
                    let kw = self.edt_kw.text();
                    if kw == "" {
                        nwg::modal_error_message(&self.window, "提示", "描述为空");
                        return;
                    }
            
                    let chx_pub = self.chx_pub.check_state();
                    let pub_state: u8;
                    match chx_pub {
                        nwg::CheckBoxState::Checked => pub_state = 1,
                        nwg::CheckBoxState::Unchecked => pub_state = 0,
                        nwg::CheckBoxState::Indeterminate => pub_state = 1,
                    }
            
                    let chx = self.chx_lock.check_state();
                    let lock_state: u8;
                    match chx {
                        nwg::CheckBoxState::Checked => lock_state = 1,
                        nwg::CheckBoxState::Unchecked => lock_state = 0,
                        nwg::CheckBoxState::Indeterminate => lock_state = 1,
                    }
                   
                    if let Err(e) = upload_art(&my_data.token, &my_data.md_file, &title, &kw, pub_state, lock_state)
                    {
                        nwg::modal_error_message(&self.window, "提示", &e.to_string());
                    } else {
                        nwg::modal_info_message(&self.window, "提示", "上传成功");
                    }

                }
                Err(e) => {
                    nwg::modal_error_message(&self.window, "提示", &e.to_string());
                    return;
                }
            }
        }else{
            if my_data.md_file.is_empty() {
                nwg::modal_error_message(&self.window, "提示", "Markdown文件为空");
                return;
            }
    
            let title = self.edt_title.text();
            if title == "" {
                nwg::modal_error_message(&self.window, "提示", "标题为空");
                return;
            }
    
            let kw = self.edt_kw.text();
            if kw == "" {
                nwg::modal_error_message(&self.window, "提示", "描述为空");
                return;
            }
    
            let chx_pub = self.chx_pub.check_state();
            let pub_state: u8;
            match chx_pub {
                nwg::CheckBoxState::Checked => pub_state = 1,
                nwg::CheckBoxState::Unchecked => pub_state = 0,
                nwg::CheckBoxState::Indeterminate => pub_state = 1,
            }
    
            let chx = self.chx_lock.check_state();
            let lock_state: u8;
            match chx {
                nwg::CheckBoxState::Checked => lock_state = 1,
                nwg::CheckBoxState::Unchecked => lock_state = 0,
                nwg::CheckBoxState::Indeterminate => lock_state = 1,
            }
            if let Err(e) = upload_art(token, &my_data.md_file, &title, &kw, pub_state, lock_state)
            {
                nwg::modal_error_message(&self.window, "提示", &e.to_string());
            } else {
                nwg::modal_info_message(&self.window, "提示", "上传成功");
            }
        }

        
    }

    fn exit(&self) {
        nwg::stop_thread_dispatch();
    }
}

fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");
    nwg::Font::set_global_family("Segoe UI").expect("Failed to set default font");

    let _app = MainApp::build_ui(Default::default()).expect("Failed to build UI");

    nwg::dispatch_thread_events();
}
